// autofire support, added by regret
// only support P1 and P2 first 4 buttons
// it's easy to add autofire for other players/buttons but I have no interest ^^

/* changelog:
 update 6: add class Autofire
 update 5: extend autofire support to 6 buttons
 update 4: chang autofire clear timer, add method2 for pgm games
 update 3: change autofire delay
 update 2: add check button state, it will not conflict with combo keys
 update 1: create
*/

#ifndef NO_AUTOFIRE

#include "burner.h"
#include "autofire.h"

Autofire autofire;

Autofire::Autofire()
{
	enabled = 1;
	defaultDelay = 3;
	delay = 3;

	delayCounter = delay;
	method2 = false;
}

Autofire::~Autofire()
{
}

// check other buttons state
// only if [player][button] clicked, return true
inline bool Autofire::checkState(int player, int fire)
{
#if 1
	if (player < P_1 || player > P_4
		|| fire < F_1 || fire > F_6) {
		return false;
	}

	static GameInp* gi = gameInput;
	static unsigned short val = 0;

	for (int j = 0; j < MAX_AUTOFIRE_BUTTONS; j++) {
		if (j != fire && !autofireOn[P_1][F_1 + j]
			&& autofires[P_1 + player][F_1 + j].value && autofires[P_1 + player][F_1 + j].inpIndex >= 0) {
			val = 0;
			gi = gameInput + autofires[P_1 + player][F_1 + j].inpIndex;
			if (gi->Input.pVal) {
				val = *gi->Input.pVal;
			}

			if (val == 1) {
				return false;
			}
		}
	}
#endif

	return true;
}

// clear button value
inline void Autofire::clear()
{
	for (int i = 0; i < MAX_PLAYER; i++) {
		for (int j = 0; j < MAX_AUTOFIRE_BUTTONS; j++) {
			if (autofireOn[P_1 + i][F_1 + j] && autofires[P_1 + i][F_1 + j].value
				&& *(autofires[P_1 + i][F_1 + j].value) && checkState(P_1 + i, F_1 + j)) {
				*(autofires[P_1 + i][F_1 + j].value) = 0;
			}
		}
	}
}

// reset data
inline void Autofire::reset()
{
	for (int i = 0; i < MAX_PLAYER; i++) {
		for (int j = 0; j < MAX_AUTOFIRE_BUTTONS; j++) {
			autofires[i][j].value = NULL;
			autofires[i][j].inpIndex = -1;
			autofireOn[i][j] = false;
		}
	}
}

// init autofire buttons
void Autofire::init()
{
	if (!enabled)
		return;

	// check delay value
	if (delay < 1 || delay > 99) {
		delay = defaultDelay;
	}
	delayCounter = delay;

	// choose autofire method
	method2 = false;
	int flag = (BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK);
	if (flag == HARDWARE_IGS_PGM) {
		method2 = true;
	}

	// reset values
	reset();

	// get button info
	int nButtons = 0; // buttons per player
	int nPlayer = 0;
	int nPlayerTemp = 0;
	BurnInputInfo bii;

	for (unsigned int i = 0; i < gameInpCount; i++) {
		memset(&bii, 0, sizeof(bii));
		BurnDrvGetInputInfo(&bii, i);

		if (!bii.szName || !bii.pVal) {
			continue;
		}

		if ((bii.szName[0] == 'P' || bii.szName[0] == 'p')
			&& bii.szName[1] >= '1' && bii.szName[1] <= '4') {
			nPlayer = bii.szName[1] - '1';

			if (nPlayer != nPlayerTemp) {
				// if it is next player
//				autofireSize = nButtons;
				nButtons = 0;
			}
			if (!strncmp(" fire", bii.szInfo + 2, 5) && nButtons < MAX_AUTOFIRE_BUTTONS) {
				autofires[nPlayer][nButtons].value = bii.pVal;
				autofires[nPlayer][nButtons].inpIndex = i;
				nButtons++;
			}

			nPlayerTemp = nPlayer;
		}
	}
}

// do autofire check every frame
void Autofire::run()
{
	if (!enabled)
		return;

	// autofire delay
	if (delayCounter > 0) {
		delayCounter--;

		if (method2) {
			clear();
		}

		return;
	}
	delayCounter = delay;

	if (!method2) {
		clear();
	}
}

// enable/disable autofire buttons
int Autofire::set(int player, int fire, bool state)
{
	if (!enabled)
		return 0;

	if (player < P_1 || player > P_4
		|| fire < F_1 || fire > F_6) {
		return 1;
	}

	autofireOn[player][fire] = state;
	return 0;
}

bool Autofire::get(int player, int fire)
{
	if (!enabled)
		return false;

	if (player < P_1 || player > P_4
		|| fire < F_1 || fire > F_6) {
		return false;
	}
	return autofireOn[player][fire];
}

#endif
